# -*- encoding:utf-8 -*-
import sys,os

from twisted.application import internet, service
from twisted.internet import protocol, reactor, defer,threads
from twisted.python import log,logfile

from utils import create_instance
from utils.daemon import Daemon
from dbproxy import DBProxy
from passportproxy import PassportProxy
from models import Charge,Card
import config
from optparse import OptionParser

class ChargeServer(Daemon):

    def __init__(self):
        self.sp_servers = {}
        self.__config_sp_servers()
        self.db_server = DBProxy().server
        self.proxy = PassportProxy(self)
        super(ChargeServer,self).__init__(config.pidfile)

    def __config_sp_servers(self):
        for key in config.sp_dict:
            sp_class_name,type,port = config.sp_dict[key]
            sp_server = create_instance(sp_class_name,port,self)
            self.sp_servers[key] = sp_server

    def response_from_sp(self,data):
        """ 收到服务商响应，更新充值卡状态
            此方法不应该被短信服务商调用
        """
        d = self.db_server.update_card_status(data['status'],data['serial'])
        return d

    def card_charge(self,data):
        """ 卡片服务商充值，先组建充值信息，再调用真正的充值方法"""
        serial = data['serial']
        d = self.db_server.get_card(serial)
        d.addCallback(lambda m:Charge(*m[0],notify=1))
        return d.addCallback(self.charge)

    def charge(self,charge_info):
        """ 充值: 服务商--> Charger --> Passport """
        d = threads.deferToThread(self.db_server.add_charge,charge_info)
        # 非单机通知passport
        if charge_info.notify == 1:
            d.addCallback(self.proxy.passport_server.charge)
            d.addCallback(lambda _:self.db_server.success_charge(charge_info.orderid))
        d.addErrback(self._charge_fail)
        return d


    def request_charge(self,card):
        """ 请求充值: Passport-->Charger-->服务商 """
        d = threads.deferToThread(self.db_server.add_card,card)
        server = self.sp_servers[card.spname]
        #XXX 用d.addCallback(server.request_charge,card)这种方式会多传一个参数
        d.addCallback(lambda _:server.request_charge(card))
        d.addErrback(self._request_charge_fail)
        return d

    def _charge_fail(self,error):
        log.err("charge failed for: %s"%error.value)

    def _request_charge_fail(self,error):
        log.err("request charge failed for: %s"%error.value)

    def run(self):
        """ 启动服务 """
        for server in self.sp_servers.values():
            server.start()
        self.proxy.start()
        reactor.run()

def main():
    parser = OptionParser()
    parser.add_option("-l", "--log", dest="filename",
                      help="write log to FILE", metavar="FILE")
    parser.add_option("-a", "--action", dest="action",
                      help="[start/stop/restart/fg]",)
    options, args = parser.parse_args()
    
    charge_server = ChargeServer()
    if options.action == 'start':
        charge_server.start()
    elif options.action == 'stop':
        charge_server.stop()
    elif options.action == 'restart':
        charge_server.restart()
    elif options.action == 'fg':
        charge_server.run()
    else:
        print parser.print_help()
        return
    filename = options.filename
    if filename:
        f = logfile.DailyLogFile(filename,os.getcwd())
        log.startLogging(f)
    else:
        log.startLogging(sys.stdout)

if __name__ == '__main__':
    main()
